home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / a_utils / yacc / flexyacc / aflex.lha / aflex / src / nfaB.a < prev    next >
Text File  |  1991-05-16  |  19KB  |  575 lines

  1. -- Copyright (c) 1990 Regents of the University of California.
  2. -- All rights reserved.
  3. --
  4. -- This software was developed by John Self of the Arcadia project
  5. -- at the University of California, Irvine.
  6. --
  7. -- Redistribution and use in source and binary forms are permitted
  8. -- provided that the above copyright notice and this paragraph are
  9. -- duplicated in all such forms and that any documentation,
  10. -- advertising materials, and other materials related to such
  11. -- distribution and use acknowledge that the software was developed
  12. -- by the University of California, Irvine.  The name of the
  13. -- University may not be used to endorse or promote products derived
  14. -- from this software without specific prior written permission.
  15. -- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16. -- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17. -- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  
  19. -- TITLE NFA construction routines
  20. -- AUTHOR: John Self (UCI)
  21. -- DESCRIPTION builds the NFA.
  22. -- NOTES this file mirrors flex as closely as possible.
  23. -- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/nfaB.a,v 1.6 90/01/12 15:20:27 self Exp Locker: self $ 
  24.  
  25. with MISC_DEFS, NFA, MISC, ECS; 
  26. with TSTRING, INT_IO, TEXT_IO, EXTERNAL_FILE_MANAGER; use MISC_DEFS, TSTRING, 
  27.   EXTERNAL_FILE_MANAGER; 
  28.  
  29. package body NFA is 
  30.  
  31. -- add_accept - add an accepting state to a machine
  32. --
  33. -- accepting_number becomes mach's accepting number.
  34.  
  35.   procedure ADD_ACCEPT(MACH             : in out INTEGER; 
  36.                        ACCEPTING_NUMBER : in INTEGER) is 
  37.   -- hang the accepting number off an epsilon state.  if it is associated
  38.   -- with a state that has a non-epsilon out-transition, then the state
  39.   -- will accept BEFORE it makes that transition, i.e., one character
  40.   -- too soon
  41.     ASTATE : INTEGER; 
  42.   begin
  43.     if (TRANSCHAR(FINALST(MACH)) = SYM_EPSILON) then 
  44.       ACCPTNUM(FINALST(MACH)) := ACCEPTING_NUMBER; 
  45.     else 
  46.       ASTATE := MKSTATE(SYM_EPSILON); 
  47.       ACCPTNUM(ASTATE) := ACCEPTING_NUMBER; 
  48.       MACH := LINK_MACHINES(MACH, ASTATE); 
  49.     end if; 
  50.   end ADD_ACCEPT; 
  51.  
  52.  
  53.   -- copysingl - make a given number of copies of a singleton machine
  54.   --
  55.   --     newsng - a new singleton composed of num copies of singl
  56.   --     singl  - a singleton machine
  57.   --     num    - the number of copies of singl to be present in newsng
  58.  
  59.   function COPYSINGL(SINGL, NUM : in INTEGER) return INTEGER is 
  60.     COPY : INTEGER; 
  61.   begin
  62.     COPY := MKSTATE(SYM_EPSILON); 
  63.  
  64.     for I in 1 .. NUM loop
  65.       COPY := LINK_MACHINES(COPY, DUPMACHINE(SINGL)); 
  66.     end loop; 
  67.  
  68.     return COPY; 
  69.   end COPYSINGL; 
  70.  
  71.  
  72.   -- dumpnfa - debugging routine to write out an nfa
  73.  
  74.   procedure DUMPNFA(STATE1 : in INTEGER) is 
  75.     SYM, TSP1, TSP2, ANUM : INTEGER; 
  76.     use TEXT_IO; 
  77.   begin
  78.     TEXT_IO.NEW_LINE(STANDARD_ERROR); 
  79.     TEXT_IO.NEW_LINE(STANDARD_ERROR); 
  80.     TEXT_IO.PUT(STANDARD_ERROR, 
  81.       "********** beginning dump of nfa with start state "); 
  82.     INT_IO.PUT(STANDARD_ERROR, STATE1, 0); 
  83.     TEXT_IO.NEW_LINE(STANDARD_ERROR); 
  84.  
  85.     -- we probably should loop starting at firstst[state1] and going to
  86.     -- lastst[state1], but they're not maintained properly when we "or"
  87.     -- all of the rules together.  So we use our knowledge that the machine
  88.     -- starts at state 1 and ends at lastnfa.
  89.     for NS in 1 .. LASTNFA loop
  90.       TEXT_IO.PUT(STANDARD_ERROR, "state # "); 
  91.       INT_IO.PUT(STANDARD_ERROR, NS, 4); 
  92.       TEXT_IO.PUT(ASCII.HT); 
  93.       SYM := TRANSCHAR(NS); 
  94.       TSP1 := TRANS1(NS); 
  95.       TSP2 := TRANS2(NS); 
  96.       ANUM := ACCPTNUM(NS); 
  97.  
  98.       INT_IO.PUT(STANDARD_ERROR, SYM, 5); 
  99.       TEXT_IO.PUT(STANDARD_ERROR, ":    "); 
  100.       INT_IO.PUT(STANDARD_ERROR, TSP1, 4); 
  101.       TEXT_IO.PUT(STANDARD_ERROR, ","); 
  102.       INT_IO.PUT(STANDARD_ERROR, TSP2, 4); 
  103.       if (ANUM /= NIL) then 
  104.         TEXT_IO.PUT(STANDARD_ERROR, "  ["); 
  105.         INT_IO.PUT(STANDARD_ERROR, ANUM, 0); 
  106.         TEXT_IO.PUT(STANDARD_ERROR, "]"); 
  107.       end if; 
  108.       TEXT_IO.NEW_LINE(STANDARD_ERROR); 
  109.     end loop; 
  110.  
  111.     TEXT_IO.PUT(STANDARD_ERROR, "********** end of dump"); 
  112.     TEXT_IO.NEW_LINE(STANDARD_ERROR); 
  113.   end DUMPNFA; 
  114.  
  115.   -- dupmachine - make a duplicate of a given machine
  116.   --
  117.   --     copy - holds duplicate of mach
  118.   --     mach - machine to be duplicated
  119.   --
  120.   -- note that the copy of mach is NOT an exact duplicate; rather, all the
  121.   -- transition states values are adjusted so that the copy is self-contained,
  122.   -- as the original should have been.
  123.   --
  124.   -- also note that the original MUST be contiguous, with its low and high
  125.   -- states accessible by the arrays firstst and lastst
  126.  
  127.   function DUPMACHINE(MACH : in INTEGER) return INTEGER is 
  128.     INIT, STATE_OFFSET : INTEGER; 
  129.     STATE              : INTEGER := 0; 
  130.     LAST               : INTEGER := LASTST(MACH); 
  131.     I                  : INTEGER; 
  132.   begin
  133.     I := FIRSTST(MACH); 
  134.     while (I <= LAST) loop
  135.       STATE := MKSTATE(TRANSCHAR(I)); 
  136.  
  137.       if (TRANS1(I) /= NO_TRANSITION) then 
  138.         MKXTION(FINALST(STATE), TRANS1(I) + STATE - I); 
  139.  
  140.         if ((TRANSCHAR(I) = SYM_EPSILON) and (TRANS2(I) /= NO_TRANSITION)) then 
  141.           MKXTION(FINALST(STATE), TRANS2(I) + STATE - I); 
  142.         end if; 
  143.       end if; 
  144.  
  145.       ACCPTNUM(STATE) := ACCPTNUM(I); 
  146.       I := I + 1; 
  147.     end loop; 
  148.  
  149.     if (STATE = 0) then 
  150.       MISC.AFLEXFATAL("empty machine in dupmachine()"); 
  151.     end if; 
  152.  
  153.     STATE_OFFSET := STATE - I + 1; 
  154.  
  155.     INIT := MACH + STATE_OFFSET; 
  156.     FIRSTST(INIT) := FIRSTST(MACH) + STATE_OFFSET; 
  157.     FINALST(INIT) := FINALST(MACH) + STATE_OFFSET; 
  158.     LASTST(INIT) := LASTST(MACH) + STATE_OFFSET; 
  159.  
  160.     return INIT; 
  161.   end DUPMACHINE; 
  162.  
  163.   -- finish_rule - finish up the processing for a rule
  164.   --
  165.   -- An accepting number is added to the given machine.  If variable_trail_rule
  166.   -- is true then the rule has trailing context and both the head and trail
  167.   -- are variable size.  Otherwise if headcnt or trailcnt is non-zero then
  168.   -- the machine recognizes a pattern with trailing context and headcnt is
  169.   -- the number of characters in the matched part of the pattern, or zero
  170.   -- if the matched part has variable length.  trailcnt is the number of
  171.   -- trailing context characters in the pattern, or zero if the trailing
  172.   -- context has variable length.
  173.  
  174.   procedure FINISH_RULE(MACH                : in INTEGER; 
  175.                         VARIABLE_TRAIL_RULE : in BOOLEAN; 
  176.                         HEADCNT, TRAILCNT   : in INTEGER) is 
  177.     P_MACH : INTEGER; 
  178.     use TEXT_IO; 
  179.   begin
  180.     P_MACH := MACH; 
  181.     ADD_ACCEPT(P_MACH, NUM_RULES); 
  182.  
  183.     -- we did this in new_rule(), but it often gets the wrong
  184.     -- number because we do it before we start parsing the current rule
  185.     RULE_LINENUM(NUM_RULES) := LINENUM; 
  186.  
  187.     TEXT_IO.PUT(TEMP_ACTION_FILE, "when "); 
  188.     INT_IO.PUT(TEMP_ACTION_FILE, NUM_RULES, 1); 
  189.     TEXT_IO.PUT_LINE(TEMP_ACTION_FILE, " => "); 
  190.  
  191.     if (VARIABLE_TRAIL_RULE) then 
  192.       RULE_TYPE(NUM_RULES) := RULE_VARIABLE; 
  193.  
  194.       if (PERFORMANCE_REPORT) then 
  195.         TEXT_IO.PUT(STANDARD_ERROR, "Variable trailing context rule at line "); 
  196.         INT_IO.PUT(STANDARD_ERROR, RULE_LINENUM(NUM_RULES), 1); 
  197.         TEXT_IO.NEW_LINE(STANDARD_ERROR); 
  198.       end if; 
  199.  
  200.       VARIABLE_TRAILING_CONTEXT_RULES := TRUE; 
  201.     else 
  202.       RULE_TYPE(NUM_RULES) := RULE_NORMAL; 
  203.  
  204.       if ((HEADCNT > 0) or (TRAILCNT > 0)) then 
  205.  
  206.         -- do trailing context magic to not match the trailing characters
  207.         TEXT_IO.PUT_LINE(TEMP_ACTION_FILE, 
  208.           "yy_ch_buf(yy_cp) := yy_hold_char; -- undo effects of setting up yytext"
  209.           ); 
  210.  
  211.         if (HEADCNT > 0) then 
  212.           TEXT_IO.PUT(TEMP_ACTION_FILE, " yy_cp := yy_bp + "); 
  213.           INT_IO.PUT(TEMP_ACTION_FILE, HEADCNT, 1); 
  214.           TEXT_IO.PUT_LINE(TEMP_ACTION_FILE, ";"); 
  215.         else 
  216.           TEXT_IO.PUT(TEMP_ACTION_FILE, "yy_cp := yy_cp - "); 
  217.           INT_IO.PUT(TEMP_ACTION_FILE, TRAILCNT, 1); 
  218.           TEXT_IO.PUT_LINE(TEMP_ACTION_FILE, ";"); 
  219.         end if; 
  220.  
  221.         TEXT_IO.PUT_LINE(TEMP_ACTION_FILE, "yy_c_buf_p := yy_cp;"); 
  222.         TEXT_IO.PUT_LINE(TEMP_ACTION_FILE, 
  223.           "YY_DO_BEFORE_ACTION; -- set up yytext again"); 
  224.       end if; 
  225.     end if; 
  226.  
  227.     MISC.LINE_DIRECTIVE_OUT(TEMP_ACTION_FILE); 
  228.   end FINISH_RULE; 
  229.  
  230.   -- link_machines - connect two machines together
  231.   --
  232.   --     new    - a machine constructed by connecting first to last
  233.   --     first  - the machine whose successor is to be last
  234.   --     last   - the machine whose predecessor is to be first
  235.   --
  236.   -- note: this routine concatenates the machine first with the machine
  237.   --  last to produce a machine new which will pattern-match first first
  238.   --  and then last, and will fail if either of the sub-patterns fails.
  239.   --  FIRST is set to new by the operation.  last is unmolested.
  240.  
  241.   function LINK_MACHINES(FIRST, LAST : in INTEGER) return INTEGER is 
  242.   begin
  243.     if (FIRST = NIL) then 
  244.       return LAST; 
  245.     else 
  246.       if (LAST = NIL) then 
  247.         return FIRST; 
  248.       else 
  249.         MKXTION(FINALST(FIRST), LAST); 
  250.         FINALST(FIRST) := FINALST(LAST); 
  251.         LASTST(FIRST) := MAX(LASTST(FIRST), LASTST(LAST)); 
  252.         FIRSTST(FIRST) := MIN(FIRSTST(FIRST), FIRSTST(LAST)); 
  253.         return (FIRST); 
  254.       end if; 
  255.     end if; 
  256.   end LINK_MACHINES; 
  257.  
  258.  
  259.   -- mark_beginning_as_normal - mark each "beginning" state in a machine
  260. --                            as being a "normal" (i.e., not trailing context-
  261.   --                            associated) states
  262.   --
  263.   -- The "beginning" states are the epsilon closure of the first state
  264.  
  265.   procedure MARK_BEGINNING_AS_NORMAL(MACH : in INTEGER) is 
  266.   begin
  267.     case (STATE_TYPE(MACH)) is 
  268.       when STATE_NORMAL => 
  269.  
  270.         -- oh, we've already visited here
  271.         return; 
  272.  
  273.       when STATE_TRAILING_CONTEXT => 
  274.         STATE_TYPE(MACH) := STATE_NORMAL; 
  275.  
  276.         if (TRANSCHAR(MACH) = SYM_EPSILON) then 
  277.           if (TRANS1(MACH) /= NO_TRANSITION) then 
  278.             MARK_BEGINNING_AS_NORMAL(TRANS1(MACH)); 
  279.           end if; 
  280.  
  281.           if (TRANS2(MACH) /= NO_TRANSITION) then 
  282.             MARK_BEGINNING_AS_NORMAL(TRANS2(MACH)); 
  283.           end if; 
  284.         end if; 
  285.       when others => 
  286.         MISC.AFLEXERROR("bad state type in mark_beginning_as_normal()"); 
  287.     end case; 
  288.   end MARK_BEGINNING_AS_NORMAL; 
  289.  
  290.   -- mkbranch - make a machine that branches to two machines
  291.   --
  292.   --     branch - a machine which matches either first's pattern or second's
  293. --     first, second - machines whose patterns are to be or'ed (the | operator)
  294.   --
  295.   -- note that first and second are NEITHER destroyed by the operation.  Also,
  296.   -- the resulting machine CANNOT be used with any other "mk" operation except
  297.   -- more mkbranch's.  Compare with mkor()
  298.   function MKBRANCH(FIRST, SECOND : in INTEGER) return INTEGER is 
  299.     EPS : INTEGER; 
  300.   begin
  301.     if (FIRST = NO_TRANSITION) then 
  302.       return SECOND; 
  303.     else 
  304.       if (SECOND = NO_TRANSITION) then 
  305.         return FIRST; 
  306.       end if; 
  307.     end if; 
  308.  
  309.     EPS := MKSTATE(SYM_EPSILON); 
  310.  
  311.     MKXTION(EPS, FIRST); 
  312.     MKXTION(EPS, SECOND); 
  313.  
  314.     return EPS; 
  315.   end MKBRANCH; 
  316.  
  317.  
  318.   -- mkclos - convert a machine into a closure
  319.   --
  320.   --     new - a new state which matches the closure of "state"
  321.  
  322.   function MKCLOS(STATE : in INTEGER) return INTEGER is 
  323.   begin
  324.     return NFA.MKOPT(MKPOSCL(STATE)); 
  325.   end MKCLOS; 
  326.  
  327.  
  328.   -- mkopt - make a machine optional
  329.   --
  330.   --     new  - a machine which optionally matches whatever mach matched
  331.   --     mach - the machine to make optional
  332.   --
  333.   -- notes:
  334.   --     1. mach must be the last machine created
  335.   --     2. mach is destroyed by the call
  336.  
  337.   function MKOPT(MACH : in INTEGER) return INTEGER is 
  338.     EPS    : INTEGER; 
  339.     RESULT : INTEGER; 
  340.   begin
  341.     RESULT := MACH; 
  342.     if (not SUPER_FREE_EPSILON(FINALST(RESULT))) then 
  343.       EPS := NFA.MKSTATE(SYM_EPSILON); 
  344.       RESULT := NFA.LINK_MACHINES(RESULT, EPS); 
  345.     end if; 
  346.  
  347.     -- can't skimp on the following if FREE_EPSILON(mach) is true because
  348.     -- some state interior to "mach" might point back to the beginning
  349.     -- for a closure
  350.     EPS := NFA.MKSTATE(SYM_EPSILON); 
  351.     RESULT := NFA.LINK_MACHINES(EPS, RESULT); 
  352.  
  353.     NFA.MKXTION(RESULT, FINALST(RESULT)); 
  354.  
  355.     return RESULT; 
  356.   end MKOPT; 
  357.  
  358.  
  359.   -- mkor - make a machine that matches either one of two machines
  360.   --
  361.   --     new - a machine which matches either first's pattern or second's
  362. --     first, second - machines whose patterns are to be or'ed (the | operator)
  363.   --
  364.   -- note that first and second are both destroyed by the operation
  365.   -- the code is rather convoluted because an attempt is made to minimize
  366.   -- the number of epsilon states needed
  367.  
  368.   function MKOR(FIRST, SECOND : in INTEGER) return INTEGER is 
  369.     EPS, OREND : INTEGER; 
  370.     P_FIRST    : INTEGER; 
  371.   begin
  372.     P_FIRST := FIRST; 
  373.     if (P_FIRST = NIL) then 
  374.       return SECOND; 
  375.     else 
  376.       if (SECOND = NIL) then 
  377.         return P_FIRST; 
  378.       else 
  379.  
  380.         -- see comment in mkopt() about why we can't use the first state
  381.         -- of "first" or "second" if they satisfy "FREE_EPSILON"
  382.         EPS := MKSTATE(SYM_EPSILON); 
  383.  
  384.         P_FIRST := LINK_MACHINES(EPS, P_FIRST); 
  385.  
  386.         MKXTION(P_FIRST, SECOND); 
  387.  
  388.         if ((SUPER_FREE_EPSILON(FINALST(P_FIRST))) and (ACCPTNUM(FINALST(P_FIRST
  389.           )) = NIL)) then 
  390.           OREND := FINALST(P_FIRST); 
  391.           MKXTION(FINALST(SECOND), OREND); 
  392.         else 
  393.           if ((SUPER_FREE_EPSILON(FINALST(SECOND))) and (ACCPTNUM(FINALST(SECOND
  394.             )) = NIL)) then 
  395.             OREND := FINALST(SECOND); 
  396.             MKXTION(FINALST(P_FIRST), OREND); 
  397.           else 
  398.             EPS := MKSTATE(SYM_EPSILON); 
  399.             P_FIRST := LINK_MACHINES(P_FIRST, EPS); 
  400.             OREND := FINALST(P_FIRST); 
  401.  
  402.             MKXTION(FINALST(SECOND), OREND); 
  403.           end if; 
  404.         end if; 
  405.       end if; 
  406.     end if; 
  407.  
  408.     FINALST(P_FIRST) := OREND; 
  409.     return P_FIRST; 
  410.   end MKOR; 
  411.  
  412.  
  413.   -- mkposcl - convert a machine into a positive closure
  414.   --
  415.   --    new - a machine matching the positive closure of "state"
  416.  
  417.   function MKPOSCL(STATE : in INTEGER) return INTEGER is 
  418.     EPS : INTEGER; 
  419.   begin
  420.     if (SUPER_FREE_EPSILON(FINALST(STATE))) then 
  421.       MKXTION(FINALST(STATE), STATE); 
  422.       return (STATE); 
  423.     else 
  424.       EPS := MKSTATE(SYM_EPSILON); 
  425.       MKXTION(EPS, STATE); 
  426.       return (LINK_MACHINES(STATE, EPS)); 
  427.     end if; 
  428.   end MKPOSCL; 
  429.  
  430.   -- mkrep - make a replicated machine
  431.   --
  432.   --    new - a machine that matches whatever "mach" matched from "lb"
  433.   --          number of times to "ub" number of times
  434.   --
  435.   -- note
  436. --   if "ub" is INFINITY then "new" matches "lb" or more occurrences of "mach"
  437.  
  438.   function MKREP(MACH, LB, UB : in INTEGER) return INTEGER is 
  439.     BASE_MACH, TAIL, COPY : INTEGER; 
  440.     P_MACH                : INTEGER; 
  441.   begin
  442.     P_MACH := MACH; 
  443.     BASE_MACH := COPYSINGL(P_MACH, LB - 1); 
  444.  
  445.     if (UB = INFINITY) then 
  446.       COPY := DUPMACHINE(P_MACH); 
  447.       P_MACH := LINK_MACHINES(P_MACH, LINK_MACHINES(BASE_MACH, MKCLOS(COPY))); 
  448.     else 
  449.       TAIL := MKSTATE(SYM_EPSILON); 
  450.  
  451.       for I in LB .. UB - 1 loop
  452.         COPY := DUPMACHINE(P_MACH); 
  453.         TAIL := MKOPT(LINK_MACHINES(COPY, TAIL)); 
  454.       end loop; 
  455.  
  456.       P_MACH := LINK_MACHINES(P_MACH, LINK_MACHINES(BASE_MACH, TAIL)); 
  457.     end if; 
  458.  
  459.     return P_MACH; 
  460.   end MKREP; 
  461.  
  462.   -- mkstate - create a state with a transition on a given symbol
  463.   --
  464.   --     state - a new state matching sym
  465.   --     sym   - the symbol the new state is to have an out-transition on
  466.   --
  467.   -- note that this routine makes new states in ascending order through the
  468.   -- state array (and increments LASTNFA accordingly).  The routine DUPMACHINE
  469.   -- relies on machines being made in ascending order and that they are
  470.   -- CONTIGUOUS.  Change it and you will have to rewrite DUPMACHINE (kludge
  471.   -- that it admittedly is)
  472.  
  473.   function MKSTATE(SYM : in INTEGER) return INTEGER is 
  474.   begin
  475.     LASTNFA := LASTNFA + 1; 
  476.     if (LASTNFA >= CURRENT_MNS) then 
  477.       CURRENT_MNS := CURRENT_MNS + MNS_INCREMENT; 
  478.       if (CURRENT_MNS >= MAXIMUM_MNS) then 
  479.         MISC.AFLEXERROR("input rules are too complicated (>= " & INTEGER'IMAGE(
  480.           CURRENT_MNS) & " NFA states) )"); 
  481.       end if; 
  482.  
  483.       NUM_REALLOCS := NUM_REALLOCS + 1; 
  484.  
  485.       REALLOCATE_INTEGER_ARRAY(FIRSTST, CURRENT_MNS); 
  486.       REALLOCATE_INTEGER_ARRAY(LASTST, CURRENT_MNS); 
  487.       REALLOCATE_INTEGER_ARRAY(FINALST, CURRENT_MNS); 
  488.       REALLOCATE_INTEGER_ARRAY(TRANSCHAR, CURRENT_MNS); 
  489.       REALLOCATE_INTEGER_ARRAY(TRANS1, CURRENT_MNS); 
  490.       REALLOCATE_INTEGER_ARRAY(TRANS2, CURRENT_MNS); 
  491.       REALLOCATE_INTEGER_ARRAY(ACCPTNUM, CURRENT_MNS); 
  492.       REALLOCATE_INTEGER_ARRAY(ASSOC_RULE, CURRENT_MNS); 
  493.       REALLOCATE_STATE_ENUM_ARRAY(STATE_TYPE, CURRENT_MNS); 
  494.     end if; 
  495.  
  496.     FIRSTST(LASTNFA) := LASTNFA; 
  497.     FINALST(LASTNFA) := LASTNFA; 
  498.     LASTST(LASTNFA) := LASTNFA; 
  499.     TRANSCHAR(LASTNFA) := SYM; 
  500.     TRANS1(LASTNFA) := NO_TRANSITION; 
  501.     TRANS2(LASTNFA) := NO_TRANSITION; 
  502.     ACCPTNUM(LASTNFA) := NIL; 
  503.     ASSOC_RULE(LASTNFA) := NUM_RULES; 
  504.     STATE_TYPE(LASTNFA) := CURRENT_STATE_ENUM; 
  505.  
  506.     -- fix up equivalence classes base on this transition.  Note that any
  507.     -- character which has its own transition gets its own equivalence class.
  508.     -- Thus only characters which are only in character classes have a chance
  509.     -- at being in the same equivalence class.  E.g. "a|b" puts 'a' and 'b'
  510.     -- into two different equivalence classes.  "[ab]" puts them in the same
  511.     -- equivalence class (barring other differences elsewhere in the input).
  512.     if (SYM < 0) then 
  513.  
  514.       -- we don't have to update the equivalence classes since that was
  515.       -- already done when the ccl was created for the first time
  516.       null; 
  517.     else 
  518.       if (SYM = SYM_EPSILON) then 
  519.         NUMEPS := NUMEPS + 1; 
  520.       else 
  521.         if (USEECS) then 
  522.           ECS.MKECHAR(SYM, NEXTECM, ECGROUP); 
  523.         end if; 
  524.       end if; 
  525.     end if; 
  526.  
  527.     return LASTNFA; 
  528.   end MKSTATE; 
  529.  
  530.   -- mkxtion - make a transition from one state to another
  531.   --
  532.   --     statefrom - the state from which the transition is to be made
  533.   --     stateto   - the state to which the transition is to be made
  534.  
  535.   procedure MKXTION(STATEFROM, STATETO : in INTEGER) is 
  536.   begin
  537.     if (TRANS1(STATEFROM) = NO_TRANSITION) then 
  538.       TRANS1(STATEFROM) := STATETO; 
  539.     else 
  540.       if ((TRANSCHAR(STATEFROM) /= SYM_EPSILON) or (TRANS2(STATEFROM) /= 
  541.         NO_TRANSITION)) then 
  542.         MISC.AFLEXFATAL("found too many transitions in mkxtion()"); 
  543.       else 
  544.  
  545.         -- second out-transition for an epsilon state
  546.         EPS2 := EPS2 + 1; 
  547.         TRANS2(STATEFROM) := STATETO; 
  548.       end if; 
  549.     end if; 
  550.   end MKXTION; 
  551.  
  552.   -- new_rule - initialize for a new rule
  553.   --
  554.   -- the global num_rules is incremented and the any corresponding dynamic
  555.   -- arrays (such as rule_type()) are grown as needed.
  556.  
  557.   procedure NEW_RULE is 
  558.   begin
  559.     NUM_RULES := NUM_RULES + 1; 
  560.     if (NUM_RULES >= CURRENT_MAX_RULES) then 
  561.       NUM_REALLOCS := NUM_REALLOCS + 1; 
  562.       CURRENT_MAX_RULES := CURRENT_MAX_RULES + MAX_RULES_INCREMENT; 
  563.       REALLOCATE_RULE_ENUM_ARRAY(RULE_TYPE, CURRENT_MAX_RULES); 
  564.       REALLOCATE_INTEGER_ARRAY(RULE_LINENUM, CURRENT_MAX_RULES); 
  565.     end if; 
  566.  
  567.     if (NUM_RULES > MAX_RULE) then 
  568.       MISC.AFLEXERROR("too many rules  (> " & INTEGER'IMAGE(MAX_RULE) & ")!"); 
  569.     end if; 
  570.  
  571.     RULE_LINENUM(NUM_RULES) := LINENUM; 
  572.   end NEW_RULE; 
  573.  
  574. end NFA; 
  575.